﻿using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using OpenCvSharp.WpfExtensions;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using static 摸鱼._数据库;
using static 摸鱼._数据库._方案;
using static 摸鱼._数据库._方案._步骤;
using static 摸鱼.全局类;
using static 摸鱼.核心;
using static 摸鱼.键鼠.钩子;
using Application = System.Windows.Application;
using Brush = System.Windows.Media.Brush;
using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color;
using ColorConverter = System.Windows.Media.ColorConverter;
using ComboBox = System.Windows.Controls.ComboBox;
using ContextMenu = System.Windows.Controls.ContextMenu;
using HorizontalAlignment = System.Windows.HorizontalAlignment;
using KeyEventArgs = System.Windows.Input.KeyEventArgs;
using Label = System.Windows.Controls.Label;
using MessageBox = System.Windows.MessageBox;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using MouseEventHandler = System.Windows.Input.MouseEventHandler;
using RichTextBox = System.Windows.Controls.RichTextBox;
using Screen = System.Windows.Forms.Screen;
using TextBox = System.Windows.Controls.TextBox;
using Timer = System.Windows.Forms.Timer;
using TreeView = System.Windows.Controls.TreeView;
namespace 摸鱼
{
    public partial class MainWindow : System.Windows.Window
    {
        public static MainWindow This;
        public static bool Stop;
        public static ConcurrentQueue<Action> 任务s = new();
        public MainWindow()
        {
            InitializeComponent();
            This = this;
            Border1.MouseLeftButtonDown += (o, e) => DragMove();
        }
        //关闭窗口, 退出程序
        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            Dispose();
            Thread.Sleep(100);
            Environment.Exit(0);
            void Dispose()
            {
                声音.清理();
                MoyuThreadPool.全局池.Dispose();
                MoyuDelay.Dispose();
                Stop = true;
                键鼠.钩子.鼠标按键.Dispose();
                键鼠.钩子.键盘按键.Dispose();
                方法Action.Dispose();
            }
        }
        private void 摸鱼_Loaded(object sender, RoutedEventArgs e)
        {
            var 数据 = 读档();
            //if (!数据.检查所有方法参数())
            //    数据 = 读档(true);
            数据库 = 数据.版本检查(true);

            MoyuThreadPool.全局池 = new(数据.参数[CS.maxThreadCount][valueType.Int]);
            // 定时器初始化
            MoyuDelay.初始化(4);

            检查变量ID去重();
            createFunction();

            屏幕宽度 = Screen.PrimaryScreen.Bounds.Width;
            屏幕高度 = Screen.PrimaryScreen.Bounds.Height;


            删除多余父方案(数据库.方案, null);
            void 删除多余父方案(List<_方案> items, _方案 父)
            {
                foreach (var item in items)
                {
                    item.父?.Clear();
                    if (父 != null)
                        item.父?.Add(父);
                    删除多余父方案(item.子, item);
                }
            }
            UI刷新.检查全局参数();
            UI刷新.方案();
            数据库.检查所有步骤参数();
            数据库.检查所有方法参数();

            //UI刷新.数据绑定(this);

            事件.初始化(this);
            声音.初始化();
            截屏.初始化();


            //将装饰器添加到窗口的Content控件上
            var c = this.Content as UIElement;
            var layer = AdornerLayer.GetAdornerLayer(c);
            layer.Add(new WindowResizeAdorner(c));

            //初始方案
            MoyuThreadPool.Post(() =>
            {
                try
                {
                    Thread.Sleep(800);
                    string[] 方案组 = 数据库.参数[CS.初始启动方案].值.Split(',');
                    if (方案组.Length == 0)
                        return;
                    递归(数据库.方案);
                    void 递归(List<_方案> 方案)
                    {
                        foreach (var item in 方案)
                        {
                            foreach (var items in 方案组)
                                if (item.名字 == items)
                                    事件.开始键触发(item);
                            if (item.子.Count != 0)
                                递归(item.子);
                        }
                    }
                }
                finally
                {

                }
            });

            初始化完成 = true;
            this.Topmost = true;

            upWinLayout();

            //提高线程优先级
            Thread.CurrentThread.Priority = ThreadPriority.BelowNormal;
            Dispatcher.BeginInvoke(() =>
            {
                System.Windows.Threading.Dispatcher.ExitAllFrames();
                while (!Stop)
                {
                    Dispatcher.Invoke(() => { }, DispatcherPriority.SystemIdle);
                    MoyuDelay.Star(9);
                    while (任务s.TryDequeue(out var item))
                        item();
                }
            }, DispatcherPriority.SystemIdle);
        }




        private void createFunction()
        {
            数据库.变量["Rand"] = new(() => random.NextDouble().ToString());
            数据库.变量["rand"] = new(() => random.NextDouble().ToString());
            数据库.变量["时间戳"] = new(() => 时间戳.ToString());
            数据库.变量["π"] = new(Math.PI.ToString);
            数据库.变量["圆周率"] = new(Math.PI.ToString);
            数据库.变量["鼠标位置"] = new(() => string.Join(',', System.Windows.Forms.Cursor.Position.Select(x => x)));
            数据库.变量["鼠标坐标"] = new(() => string.Join(',', System.Windows.Forms.Cursor.Position.Select(x => x)));
        }
        private void upWinLayout()
        {
            if (数据库.winW != 0)
                this.Width = 数据库.winW;
            if (数据库.winH != 0)
                this.Height = 数据库.winH;

            if (数据库.winRow[0] != -99)
            {
                var rowLayout = MainWindow.This.winLayout.RowDefinitions;
                for (int i = 0; i < rowLayout.Count; i++)
                    rowLayout[i].Height = new(数据库.winRow[i], GridUnitType.Star);
                var columnLayout = MainWindow.This.winLayout.ColumnDefinitions;
                for (int i = 0; i < columnLayout.Count; i++)
                    columnLayout[i].Width = new(数据库.winColumn[i], GridUnitType.Star);
            }
            if (数据库.winX != 0 && this is System.Windows.Window window)
            {
                window.Left = 数据库.winX;
                window.Top = 数据库.winY;
            }
            LocationChanged += (o, e) =>
            {
                if (this is System.Windows.Window window)
                {
                    数据库.winX = window.Left;
                    数据库.winY = window.Top;
                    存档();
                }
            };
        }
        private void 摸鱼_Activated(object sender, EventArgs e)
        {
            this.Topmost = true;
        }
        private void 列表_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (sender is ContextMenu)
            {
                e.Handled = true;
                return;
            }
            TreeViewItem viewItem = (TreeViewItem)((TreeView)sender).SelectedItem;
            if ((viewItem != null && viewItem.Header is TextBox) || 方法监听)
                return;
            switch (e.Key)
            {
                case Key.Up:
                    break;
                case Key.Left:
                    break;
                case Key.Right:
                    break;
                case Key.Down:
                    break;
                case Key.C:
                    break;
                case Key.X:
                    break;
                case Key.V:
                    break;
                case Key.R:
                    break;
                case Key.D:
                    break;
                case Key.Delete:
                    break;
                default:
                    e.Handled = true;
                    break;
            }
        }


        private void Label_MouseDown(object sender, MouseButtonEventArgs e)
        {
            Label label = (Label)sender;
            string labelstr = ((string)label.Content).Substring(0, 2);
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                switch (labelstr)
                {
                    case "方案":
                        列表视图刷新(null, 层级.方案);
                        break;
                    case "步骤":
                        列表视图刷新(null, 层级.步骤);
                        break;
                    case "方法":
                        列表视图刷新(null, 层级.方法);
                        break;
                    case "参数":
                        列表视图刷新(null, 层级.参数);
                        break;
                    case "变量":
                        列表视图刷新(null, 层级.变量);
                        break;
                    case "数据":
                        列表视图刷新(null, 层级.数据);
                        break;
                    case "线程":
                        列表视图刷新(null, 层级.线程);
                        break;
                }
            }
            else if (e.RightButton == MouseButtonState.Pressed)
            {
                switch (labelstr)
                {
                    case "方案":
                        列表视图刷新(null, 层级.方案);
                        方案右键菜单.Placement = PlacementMode.Mouse;
                        方案右键菜单.IsOpen = true;
                        break;
                    case "步骤":
                        列表视图刷新(null, 层级.步骤);
                        步骤右键菜单.Placement = PlacementMode.Mouse;
                        步骤右键菜单.IsOpen = true;
                        break;
                    case "方法":
                        列表视图刷新(null, 层级.方法);
                        方法右键菜单.Placement = PlacementMode.Mouse;
                        方法右键菜单.IsOpen = true;
                        break;
                    case "参数":
                        列表视图刷新(null, 层级.参数);
                        参数右键菜单.Placement = PlacementMode.Mouse;
                        参数右键菜单.IsOpen = true;
                        break;
                    case "变量":
                        列表视图刷新(null, 层级.变量);
                        变量右键菜单.Placement = PlacementMode.Mouse;
                        变量右键菜单.IsOpen = true;
                        break;
                    case "数据":
                        列表视图刷新(null, 层级.数据);
                        变量右键菜单.Placement = PlacementMode.Mouse;
                        变量右键菜单.IsOpen = true;
                        break;
                    case "线程":
                        列表视图刷新(null, 层级.线程);
                        线程右键菜单.Placement = PlacementMode.Mouse;
                        线程右键菜单.IsOpen = true;
                        break;
                }
            }
        }

        private void 删除方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (方案列表.SelectedItem == null)
                    return;
                if (MoyuControl.Msgbox($"确定要删除 {数据库.当前方案.名字} 吗"))
                {
                    方案列表数据.Remove(数据库.当前方案, true);
                    存档();
                }
            });
        }
        public void 删除方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (方法列表.SelectedItem == null)
                    return;
                if (MoyuControl.Msgbox($"确定要删除 {数据库.当前方法.名字} 吗"))
                {
                    方法列表数据.Remove(数据库.当前方法);
                    存档();
                }
            });
        }
        private void 添加方案_Click(object sender, RoutedEventArgs e)
        {
            if (数据库.方案 == null)
                数据库.方案 = new List<_方案>();
            方案列表数据.Add(数据库.当前方案, new _方案($"方案{数据库.方案ID += 1}"));
            方案列表数据[数据库.当前方案].展开();
            存档();
        }
        private void 添加步骤_Click(object sender, RoutedEventArgs e)
        {
            if (!步骤列表数据.Add(new _步骤()))
                return;
            "0".创建变量(数据库.当前步骤, $"图片{数据库.变量闲ID.Dequeue()}", "图片");
            "0".创建变量(数据库.当前步骤, $"位置{数据库.变量闲ID.Dequeue()}", "数值");
            "0".创建变量(数据库.当前步骤, $"目标{数据库.变量闲ID.Dequeue()}", "数值");
            "0,0,1920,1080".创建变量(数据库.当前步骤, $"区域{数据库.变量闲ID.Dequeue()}", "数值");
            UI刷新.变量();
            存档();
        }

        private void 删除步骤_Click(object sender, RoutedEventArgs e)
        {
            if (步骤列表.SelectedItem == null)
                return;
            var 元组 = 步骤列表.Get节点数据<_步骤>();
            if (MoyuControl.Msgbox($"确定要删除 {元组.对象.名字}{元组.索引 + 1} 吗"))
            {
                步骤列表数据.Remove(数据库.当前步骤, true);
                存档();
            }
        }
        private bool UI刷新中 = false;
        private void 列表视图刷新(TreeViewItem 选择项, 层级 层级)
        {
            if (UI刷新中 == true || 初始化完成 == false)
                return;
            UI刷新中 = true;
            switch (层级)
            {
                case 层级.方案:
                    if (数据库.当前方案 != 选择项?.Get节点数据<_方案>().对象)
                    {
                        数据库.当前方案 = 选择项?.Get节点数据<_方案>().对象;
                        数据库.选中节点 = 数据库.当前方案;
                        数据库.当前步骤 = null;
                        数据库.当前方法 = null;
                        数据库.当前参数 = null;
                        数据库.当前变量 = null;
                        UI刷新.步骤();
                        UI刷新.方法();
                        UI刷新.变量();
                        UI刷新.变量数据();

                        if (数据库.当前方案 is null)
                        {
                            if (方案列表.SelectedItem is TreeViewItem x && x != null)
                                x.IsSelected = false;
                            UI刷新.参数(层级.None);
                        }
                        else
                            UI刷新.参数(层级.方案);
                    }
                    break;
                case 层级.步骤:
                    if (数据库.当前步骤 != 选择项?.Get节点数据<_步骤>().对象)
                    {
                        数据库.当前步骤 = 选择项?.Get节点数据<_步骤>().对象;
                        数据库.选中节点 = 数据库.当前步骤;
                        数据库.当前方法 = null;
                        数据库.当前参数 = null;
                        数据库.当前变量 = null;
                        UI刷新.方法();
                        UI刷新.变量();
                        UI刷新.变量数据();

                        if (数据库.当前步骤 is null)
                        {
                            if (步骤列表.SelectedItem is TreeViewItem x && x != null)
                                x.IsSelected = false;
                            UI刷新.参数(层级.方案);
                        }
                        else
                            UI刷新.参数(层级.步骤);
                    }
                    break;
                case 层级.方法:
                    if (数据库.当前方法 != 选择项?.Get节点数据<_方法>().对象)
                    {
                        数据库.当前方法 = 选择项?.Get节点数据<_方法>().对象;
                        数据库.选中节点 = 数据库.当前方法;
                        数据库.当前参数 = null;

                        if (数据库.当前方法 is null)
                        {
                            if (方法列表.SelectedItem is TreeViewItem x && x != null)
                                x.IsSelected = false;
                            UI刷新.参数(层级.步骤);
                        }
                        else
                            UI刷新.参数(层级.方法);
                    }
                    break;
                case 层级.参数:
                    移除焦点();
                    数据库.当前变量 = null;
                    if (变量列表.SelectedItem is TreeViewItem x1 && x1 != null)
                        x1.IsSelected = false;

                    参数改变(选择项);
                    break;
                case 层级.变量:
                    if (数据库.当前变量 != (string?)选择项?.Header)
                    {
                        数据库.当前变量 = (string?)选择项?.Header;
                        数据库.选中节点 = 数据库.当前变量;
                        UI刷新.变量数据();

                        if (数据库.当前变量 is null)
                        {
                            if (变量列表.SelectedItem is TreeViewItem x && x != null)
                                x.IsSelected = false;
                        }

                        数据库.当前参数 = null;
                        if (参数列表.SelectedItem is TreeViewItem item && item is not null)
                            item.IsSelected = false;
                    }
                    break;
                case 层级.数据:
                    if (选择项 == null)
                        移除焦点();
                    break;
                case 层级.线程:
                    if (选择项 is null)
                    {
                        if (线程列表.SelectedItem is TreeViewItem item && item is not null)
                            item.IsSelected = false;
                    }
                    break;
            }
            UI刷新中 = false;
            存档();
        }
        private void 方案列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)方案列表.SelectedItem, 层级.方案);
        }
        public void 步骤列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)步骤列表.SelectedItem, 层级.步骤);
        }
        public void 方法列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)方法列表.SelectedItem, 层级.方法);
        }
        public void 参数列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)参数列表.SelectedItem, 层级.参数);
        }
        private void 变量列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)变量列表.SelectedItem, 层级.变量);
            UI刷新.变量数据();

            if (数据库.当前变量 == null)
            {
                TreeViewItem item = (TreeViewItem)变量列表.SelectedItem;
                if (item is not null)
                    item.IsSelected = false;
                移除焦点();
            }
        }
        private void 线程列表_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
            列表视图刷新((TreeViewItem)线程列表.SelectedItem, 层级.线程);
        }
        public void 变量类型下拉框_SelectionChanged(object sender, RoutedEventArgs e)
        {
            ComboBoxItem 选中 = (ComboBoxItem)变量类型下拉框.SelectedItem;
            if (选中 == null || 数据库.当前变量 == null) return;
            string 类型 = 选中.Content.ToString();
            string 变量名 = 数据库.当前变量;
            switch (类型)
            {
                case "数值":
                    编译.类型转换(变量名, "数值");
                    break;
                case "文本":
                    编译.类型转换(变量名, "文本");
                    break;
                case "图片":
                    编译.类型转换(变量名, "图片");
                    break;
            }
            UI刷新.变量数据();
        }

        private async void 添加方法_Click(object sender, RoutedEventArgs e)
        {
            方法列表数据.Add(数据库.当前方法, new _方法((string)((MenuItem)sender).Header));
            方法列表数据[数据库.当前方法].展开();
            存档();
        }
        private void 添加变量_Click(object sender, RoutedEventArgs e)
        {
            switch ((string)((MenuItem)sender).Header)
            {
                case "创建步骤变量":
                    "0".创建变量(数据库.当前步骤);
                    break;
                case "创建方案变量":
                    "0".创建变量(数据库.当前方案);
                    break;
                case "创建全局变量":
                    "0".创建变量(数据库);
                    break;
            }
            数据库.当前变量 = null;
            UI刷新.清空数据列表();
            UI刷新.变量();
            存档();
        }

        private bool is添加数据;
        public bool 强制改变数据;
        public ThreadDoublebuffering 数据输入框任务s = new();
        private Stack<string> 数据输入框文本s = new();
        public void 数据输入框_TextChanged(object sender, TextChangedEventArgs e)
        {
            RichTextBox richTextBox = sender as RichTextBox;
            if (richTextBox == null)
                is添加数据 = true;
            else
            {
                TextRange textRange = new TextRange(richTextBox.Document.ContentStart, richTextBox.Document.ContentEnd);
                string 纯文本内容 = textRange.Text;
                int 添加长度 = 0;
                foreach (TextChange change in e.Changes)
                    添加长度 = change.AddedLength + 添加长度 - change.RemovedLength;
                is添加数据 = 添加长度 > 0;
                Console.WriteLine($"文本变化 - 位置:{e.Changes.First().Offset}, 移除:{e.Changes.First().RemovedLength}, 添加:{e.Changes.First().AddedLength}");
            }
            数据输入框文本s.Push(数据输入框.取出文本());
            数据输入框任务s.Enqueue(() => MainWindow.任务s.Enqueue(数据输入框改变));
        }
        public void 数据输入框改变()
        {
            if (数据库.当前参数 != null)
            {
                if (数据输入框文本s.TryPop(out var result))
                {
                    数据输入框文本s.Clear();
                    数据库.当前参数.值 = result;
                    ((TreeViewItem)参数列表.SelectedItem).Header = 数据库.当前参数.文本值合并();
                    存档();
                }
                return;
            }

            if (数据库.当前变量 == null || 初始化完成 == false || Keyboard.FocusedElement != 数据输入框 && 强制改变数据 == false)
                return;
            强制改变数据 = false;
            TreeViewItem 选中变量控件 = (TreeViewItem)变量列表.SelectedItem;
            if (数据库.变量[数据库.当前变量].类型 == "图片" || 数据输入框.有图())
            {
                if (选中变量控件 == null)
                {
                    数据输入框.图片().创建变量("图片", "图片");
                    选中新变量();
                }
                else
                {
                    string 变量名 = 数据库.当前变量;
                    变量名.取值(out _变量 变量);
                    if (变量.类型 == "图片")
                    {
                        var bitmaps = 数据输入框.图片();
                        if (is添加数据 && bitmaps.Count == 0)
                        {
                            try
                            {
                                if (System.Windows.Clipboard.ContainsImage())
                                {
                                    BitmapSource clipboardImage = System.Windows.Clipboard.GetImage();
                                    if (clipboardImage != null)
                                    {
                                        bitmaps.Add(new(clipboardImage));
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                // 忽略剪贴板访问异常
                                System.Diagnostics.Debug.WriteLine($"访问剪贴板失败: {ex.Message}");
                            }
                        }
                        变量名.覆盖图片(bitmaps);
                    }
                    else
                    {
                        数据输入框.图片().创建变量("图片", "图片");
                        选中新变量();
                    }
                }
            }
            else if (选中变量控件 != null)
            {
                if (数据输入框文本s.TryPop(out var result))
                {
                    数据输入框文本s.Clear();
                    string 变量名 = (string)选中变量控件.Header;
                    变量名.赋值(result);
                }
            }
            else if (数据输入框文本s.TryPop(out var result))
            {
                数据输入框文本s.Clear();
                if (double.TryParse(result, out _))
                    result.创建变量("变量", "数值");
                else
                    result.创建变量("变量", "文本");
                选中新变量();
            }
            存档();
        }

        private async void 参数改变(TreeViewItem 参数item)
        {
            在监听参数.失去焦点 = true;
            数据库.当前变量 = null;
            数据库.当前参数 = (_参数)参数item?.Tag;
            数据输入框.TextChanged -= 数据输入框_TextChanged;
            数据输入框.替换文本(数据库.当前参数?.值 ?? "");
            数据输入框.TextChanged += 数据输入框_TextChanged;
            if (参数item == null)
            {
                if (参数列表.SelectedItem is TreeViewItem item && item is not null)
                    item.IsSelected = false;
                return;
            }

            在监听参数.节点 = 参数item;
            string 节点名 = (string)在监听参数.节点.Header;
            if (节点名.Length < 5)
                return;
            bool 监听键盘 = false;
            switch (节点名.Substring(0, 5))
            {
                case "开始快捷键":
                    在监听参数.参数 = 数据库.参数[CS.开始键];
                    在监听参数.参数字符串 = "开始快捷键";
                    监听键盘 = true;
                    break;
                case "结束快捷键":
                    在监听参数.参数 = 数据库.参数[CS.结束键];
                    在监听参数.参数字符串 = "结束快捷键";
                    监听键盘 = true;
                    break;
                case "截图快捷键":
                    在监听参数.参数 = 数据库.参数[CS.截图键];
                    在监听参数.参数字符串 = "截图快捷键";
                    监听键盘 = true;
                    break;
                case "隐藏快捷键":
                    在监听参数.参数 = 数据库.参数[CS.隐藏键];
                    在监听参数.参数字符串 = "隐藏快捷键";
                    监听键盘 = true;
                    break;
                case "注册的按键" or "注册的键盘" or "按键 = ":
                    在监听参数.参数 = 数据库.当前方法.参数[CS.键盘按键];
                    在监听参数.参数字符串 = "注册的按键";
                    监听键盘 = true;
                    break;
                case "同步的键盘":
                    在监听参数.参数 = 数据库.当前方法.参数[CS.键盘按键2];
                    在监听参数.参数字符串 = "同步的按键";
                    监听键盘 = true;
                    break;
                case "注册的鼠标" or "鼠标按键 ":
                    在监听参数.参数 = 数据库.当前方法.参数[CS.鼠标按键];
                    在监听参数.参数字符串 = "注册的鼠标";
                    break;
                default:
                    return;
            }
            在监听参数.失去焦点 = false;
            if (监听键盘)
                键鼠.钩子.键盘Click += 参数按键监听;
            else
                键鼠.钩子.鼠标Click += 鼠标按键监听;
        }
        private SemaphoreSlim 鼠标按键单行道 = new(1, 1);
        private ConcurrentHashSet<int> 鼠标按键缓存 = new();
        public void 鼠标按键监听(List<int> 按键事件s, bool keydown)
        {
            if (鼠标按键单行道.Wait(0))
                return;

            if (鼠标按键缓存.Count > 0)
            {
                foreach (var item in 鼠标按键缓存)
                {
                    if (!按键事件s.Contains(item))
                    {
                        if (按键事件s == null)
                            在监听参数.参数.值 = "";
                        else
                            在监听参数.参数.值 = 在监听参数.按键值合并(鼠标按键缓存);

                        this.Dispatcher.Invoke(() => 在监听参数.节点.Header = 在监听参数.参数.文本值合并());
                        键鼠.钩子.鼠标Click -= 鼠标按键监听;
                        鼠标按键缓存.Clear();
                        鼠标按键单行道.Release();
                        return;
                    }
                }
            }
            if (keydown)
                foreach (var item in 按键事件s)
                    鼠标按键缓存.Add(item);
        }
        private ConcurrentHashSet<int> 键盘按键缓存 = new();
        public void 参数按键监听(List<int> 按键事件s, bool keydown)
        {
            if (键盘按键缓存.Count > 0)
            {
                foreach (var item in 键盘按键缓存)
                {
                    if (!按键事件s.Contains(item))
                    {
                        if (按键事件s == null)
                            在监听参数.参数.值 = "";
                        else
                        {
                            在监听参数.快捷键赋值(键盘按键缓存);
                            在监听参数.参数.值 = 在监听参数.按键值合并(键盘按键缓存.Select(x => (Keys)x));
                        }
                        this.Dispatcher.Invoke(() => 在监听参数.节点.Header = 在监听参数.参数.文本值合并());
                        键鼠.钩子.键盘Click -= 参数按键监听;
                        键盘按键缓存.Clear();
                        return;
                    }
                }
            }
            if (keydown)
                foreach (var item in 按键事件s)
                    键盘按键缓存.Add(item);
        }
        private void 方法按键监听(List<int> 按键事件s, bool keydown)
        {
            if (键盘按键缓存.Count > 0)
            {
                foreach (var item in 键盘按键缓存)
                {
                    if (!按键事件s.Contains(item))
                    {
                        string 显示文本 = "";
                        if (按键事件s != null)
                            显示文本 = 在监听参数.按键值合并(键盘按键缓存.Select(x => (Keys)x));
                        键盘按键缓存.Clear();
                        this.Dispatcher.Invoke(() => 添加方法_Click(new MenuItem() { Header = 显示文本 }, null));
                        return;
                    }
                }
            }
            if (keydown)
                foreach (var item in 按键事件s)
                    键盘按键缓存.Add(item);
        }
        private bool 方法监听;
        private void 方法右键菜单_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue == true)
            {
                方法监听 = true;
                键鼠.钩子.键盘Click += 方法按键监听;
            }
            else
            {
                方法监听 = false;
                键鼠.钩子.键盘Click -= 方法按键监听;
                键盘按键缓存.Clear();
            }
        }


        private void 参数列表_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            if (在监听参数.失去焦点 == false)
                e.Handled = true;
        }
        private void 参数右键菜单_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue == true)
            {
                object 鼠下节点 = 参数列表.SelectedItem;
                if (鼠下节点 == null)
                    return;
                参数右键菜单.Items.Clear();

                var 变量s = UI刷新.获取变量列表();
                foreach (string item in 变量s)
                {
                    参数右键菜单.Items.Add(new MenuItem() { Header = item });
                    ((MenuItem)参数右键菜单.Items[^1]).Click += 参数菜单项_Click;
                }
            }
            else
            {
                foreach (MenuItem 参数项 in 参数右键菜单.Items)
                    参数项.Click -= 参数菜单项_Click;
                参数右键菜单.Items.Clear();
            }
            void 参数菜单项_Click(object o, RoutedEventArgs e)
            {
                if (数据库.当前参数?.值 is not null)
                    数据库.当前参数.值 = (string)((MenuItem)e.Source).Header;
                else
                    return;
                ((TreeViewItem)参数列表.SelectedItem).Header = 数据库.当前参数.文本值合并();
                数据输入框.替换文本(数据库.当前参数.值);
            }
        }

        private void 结束选中线程_Click(object sender, RoutedEventArgs e)
        {
            核心.冷却(线程列表.SelectedItem, null);
        }
        private void 结束所有线程_Click(object sender, RoutedEventArgs e)
        {
            核心.冷却(2, default);
        }

        private void ComboBoxItem_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            if ((bool)e.NewValue)
            {
                下箭头.Visibility = Visibility.Visible;
                左箭头.Visibility = Visibility.Hidden;
            }
            else
            {
                左箭头.Visibility = Visibility.Visible;
                下箭头.Visibility = Visibility.Hidden;
            }
        }

        private void 参数列表_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (数据库.当前参数 == null)
                return;
            if (参数列表.SelectedItem is TreeViewItem viewItem && viewItem.Header == 数据库.当前参数.显示文本)
            {
                var textBox = new TextBox()
                {
                    Text = 数据库.当前参数.值,
                    Width = 参数列表.ActualWidth * 0.7,
                    Tag = ("参数", viewItem.Header)
                };
                viewItem.Header = textBox;
                当前textView = viewItem;
                TreeText设置(textBox);
            }
        }
        //viewitem文本框通用事件        
        private TreeViewItem 当前textView;
        private void TreeText设置(TextBox textBox)
        {
            textBox.ContextMenu = (ContextMenu)FindResource("输入框右键菜单");
            textBox.Loaded += TreeText_Loaded;
            textBox.KeyDown += TreeText_KeyDown;
            textBox.LostFocus += TreeText_LostFocus;
            textBox.KeyDown += 输入框_KeyDown;
        }
        private void TreeText_Loaded(object o, RoutedEventArgs e)
        {
            Keyboard.Focus((TextBox)o);
        }
        private void TreeText_KeyDown(object o, KeyEventArgs e)
        {
            if (e.Key == Key.Enter)
                ((TextBox)o).Focusable = false;
        }
        private void TreeText_LostFocus(object o, RoutedEventArgs e)
        {
            TextBox text = (TextBox)o;
            (string type, object 控件name) = (ValueTuple<string, object>)text.Tag;
            switch (type)
            {
                case "方案":
                    if (数据库.当前方案 == null) break;
                    数据库.当前方案.名字 = text.Text;
                    当前textView.Header = 数据库.当前方案.名字;
                    break;
                case "参数":
                    if (数据库.当前参数 == null) break;
                    数据库.当前参数.值 = text.Text;
                    当前textView.Header = 数据库.当前参数.文本值合并();
                    数据输入框.TextChanged -= 数据输入框_TextChanged;
                    数据输入框.替换文本(text.Text);
                    数据输入框.TextChanged += 数据输入框_TextChanged;
                    break;
                case "步骤":
                    if (数据库.当前步骤 == null)
                        break;
                    string newName = text.Text;
                    string oldName = 数据库.当前步骤.名字;

                    步骤列表数据[数据库.当前步骤].Header = ((string)控件name).Replace(oldName, newName);
                    数据库.当前步骤.名字 = newName;
                    break;
                case "变量":
                    if (数据库.当前变量 == null)
                        break;
                    数据库.当前变量 = 数据库.当前变量.改名(text.Text);
                    当前textView.Header = 数据库.当前变量;
                    break;
            }
            //解绑事件
            text.Loaded -= TreeText_Loaded;
            text.KeyDown -= TreeText_KeyDown;
            text.LostFocus -= TreeText_LostFocus;
            text.KeyDown -= 输入框_KeyDown;
            text.Visibility = Visibility.Collapsed;
            text = null; 当前textView = null;
        }
        private void 输入框_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Escape)
            {
                switch (sender)
                {
                    case TextBox:
                        ((TextBox)sender).Focusable = false;
                        break;
                    case RichTextBox:
                        移除焦点();
                        break;
                }
            }
        }


        private void 方案改名_Click(object sender, RoutedEventArgs e)
        {
            if (数据库.当前方案 == null)
                return;
            TreeViewItem viewItem = (TreeViewItem)方案列表.SelectedItem;


            var textBox = new TextBox()
            {
                Text = 数据库.当前方案.名字,
                Width = 方案列表.ActualWidth * 0.7,
                Tag = ("方案", viewItem.Header)
            };
            viewItem.Header = textBox;
            当前textView = viewItem;
            TreeText设置(textBox);
        }
        private void 步骤改名_Click(object sender, RoutedEventArgs e)
        {
            if (数据库.当前步骤 == null) { return; }
            TreeViewItem viewItem = (TreeViewItem)步骤列表.SelectedItem;

            var textBox = new TextBox()
            {
                Text = 数据库.当前步骤.名字,
                Width = 步骤列表.ActualWidth * 0.7,
                Tag = ("步骤", viewItem.Header)
            };
            viewItem.Header = textBox;
            当前textView = viewItem;
            TreeText设置(textBox);
        }

        private void 变量改名_Click(object sender, RoutedEventArgs e)
        {
            if (数据库.当前变量 == null) { return; }
            TreeViewItem viewItem = (TreeViewItem)变量列表.SelectedItem;

            var textBox = new TextBox()
            {
                Text = 数据库.当前变量,
                Width = 变量列表.ActualWidth * 0.7,
                Tag = ("变量", viewItem.Header)
            };
            viewItem.Header = textBox;
            当前textView = viewItem;
            TreeText设置(textBox);
        }

        private void TreeViewItem_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (e.RightButton != MouseButtonState.Pressed) return;
            if (!(e.OriginalSource is TreeViewItem 鼠下))
            {
                DependencyObject depObj = null;
                depObj = (DependencyObject)e.OriginalSource;
                while (depObj != null && !(depObj is TreeViewItem))
                {
                    depObj = VisualTreeHelper.GetParent(depObj);
                }
                鼠下 = depObj as TreeViewItem;
            }
            if (鼠下 != null)
            {
                鼠下.IsSelected = true;
            }
        }

        private _方法 被复制方法;
        public void 复制方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制方法 = new(数据库.当前方法);
                清除父方法(被复制方法);
                前一个复制值 = 被复制方法;
                MoyuControl.气泡("复制成功", this);
            });
        }
        public void 剪切方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制方法 = new(数据库.当前方法);
                方法列表数据.Remove(数据库.当前方法);
                清除父方法(被复制方法);
                前一个复制值 = 被复制方法;
                MoyuControl.气泡("剪切成功", this);
            });
        }
        private void 清除父方法(_方法 方法)
        {
            var 父方法 = 方法.父.FirstOrDefault();
            if (父方法 != default)
                方法.父.Clear();
        }
        public void 粘贴方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                方法列表数据.Add(数据库.当前方法, 被复制方法);
                前一个复制值 = new();
                MoyuControl.气泡("粘贴成功", this);
                方法列表数据[数据库.当前方法].展开();
            });
        }
        public void 插入方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                方法列表数据.Insert(数据库.当前方法, 被复制方法);
                被复制方法 = null;
                前一个复制值 = new();
                MoyuControl.气泡("插入成功", this);
                方法列表数据[数据库.当前方法].展开();
            });
        }
        public void 替换方法_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制方法 == null)
                    return;
                方法列表数据.Replace(数据库.当前方法, 被复制方法);
                被复制方法 = null;
                前一个复制值 = new();
                MoyuControl.气泡("替换成功", this);
                方法列表数据[数据库.当前方法].展开();
            });
        }

        private _方案 被复制方案;
        private void 复制方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制方案 = new(数据库.当前方案, true);
                前一个复制值 = 被复制方案;
                清除父方案(被复制方案);
                MoyuControl.气泡("复制成功", this);
            });
        }
        private void 剪切方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制方案 = new(数据库.当前方案, false);
                方案列表数据.Remove(数据库.当前方案, false);
                前一个复制值 = 被复制方案;
                清除父方案(被复制方案);
                MoyuControl.气泡("剪切成功", this);
            });
        }
        private void 清除父方案(_方案 方案)
        {
            var 父方案 = 方案.父.FirstOrDefault();
            if (父方案 != default)
                方案.父.Clear();
        }
        private void 粘贴方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制方案 == null)
                    return;
                方案列表数据.Add(数据库.当前方案, 被复制方案);
                被复制方案 = null;
                前一个复制值 = new();
                MoyuControl.气泡("粘贴成功", this);
                方案列表数据[数据库.当前方案].展开();
            });
        }
        public void 插入方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制方案 == null)
                    return;
                方案列表数据.Insert(数据库.当前方案, 被复制方案);
                被复制方案 = null;
                前一个复制值 = new();
                MoyuControl.气泡("插入成功", this);
                方案列表数据[数据库.当前方案].展开();
            });
        }
        private void 替换方案_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制方案 == null)
                    return;
                方案列表数据.Replace(数据库.当前方案, 被复制方案);
                被复制方案 = null;
                前一个复制值 = new();
                MoyuControl.气泡("替换成功", this);
                方案列表数据[数据库.当前方案].展开();
            });
        }

        private _步骤 被复制步骤;
        private void 复制步骤_Click(object sender, RoutedEventArgs e)
        {
            this.Dispatcher.Invoke(() =>
            {
                被复制步骤 = new(数据库.当前步骤, true);
                前一个复制值 = 被复制步骤;
                MoyuControl.气泡("复制成功", this);
            });
        }
        private void 剪切步骤_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制步骤 = new(数据库.当前步骤, false);
                步骤列表数据.Remove(数据库.当前步骤, false);
                前一个复制值 = 被复制步骤;
                MoyuControl.气泡("剪切成功", this);
            });
        }
        private void 粘贴步骤_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.This.Dispatcher.Invoke(() =>
            {
                if (被复制步骤 == null)
                    return;
                步骤列表数据.Add(被复制步骤);
                被复制步骤 = null;
                前一个复制值 = new();
                MoyuControl.气泡("粘贴成功", this);
            });
        }
        private void 插入步骤_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制步骤 == null)
                    return;
                步骤列表数据.Insert(被复制步骤);
                被复制步骤 = null;
                前一个复制值 = new();
                MoyuControl.气泡("插入成功", this);

                _步骤 选中步骤 = 数据库.当前步骤;
                UI刷新.步骤();
                if (选中步骤 != null)
                    步骤列表数据[选中步骤].IsSelected = true;
            });
        }
        private void 替换步骤_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制步骤 == null)
                    return;
                步骤列表数据.Replace(被复制步骤);
                被复制步骤 = null;
                前一个复制值 = new();
                MoyuControl.气泡("替换成功", this);

                _步骤 选中步骤 = 数据库.当前步骤;
                UI刷新.步骤();
                if (选中步骤 != null)
                    步骤列表数据[选中步骤].IsSelected = true;
            });
        }

        private object 前一个复制值;
        private (string 名字, _变量 数据) 被复制变量;
        private void 复制变量_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制变量.数据 = 数据库.变量[数据库.当前变量].Clone(true);
                被复制变量.名字 = Regex.Replace(数据库.当前变量, "\\d", "") + 数据库.变量闲ID.Dequeue();
                前一个复制值 = string.Empty;
                MoyuControl.气泡("复制成功", this);
            });
        }
        private void 剪切变量_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                被复制变量.数据 = 数据库.变量[数据库.当前变量].Clone(true);
                被复制变量.名字 = Regex.Replace(数据库.当前变量, "\\d", "") + 数据库.变量闲ID.Dequeue();
                TreeViewItem 节点 = (TreeViewItem)变量列表.SelectedItem;
                数据库.当前变量.删除变量(数据库.当前变量.Get级别());
                变量列表.Items.Remove(节点);
                前一个复制值 = string.Empty;
                MoyuControl.气泡("剪切成功", this);
            });
        }
        private void 粘贴变量_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (被复制变量 == default)
                    return;
                if (被复制变量.数据.图片.Count != 0)
                    被复制变量.数据.图片.创建变量(被复制变量.名字);
                else
                    被复制变量.数据.值.创建变量(被复制变量.名字);
                被复制变量 = default;
                前一个复制值 = new();
                数据库.当前变量 = null;
                UI刷新.清空数据列表();
                UI刷新.变量();
                MoyuControl.气泡("粘贴成功", this);
            });
        }
        private void 删除变量_Click(object sender, RoutedEventArgs e)
        {
            MainWindow.任务s.Enqueue(() =>
            {
                if (变量列表.SelectedItem == null) { return; }
                TreeViewItem 节点 = (TreeViewItem)变量列表.SelectedItem;
                var 名字 = (string)节点.Header;
                if (MoyuControl.Msgbox($"确定要删除 {名字} 吗"))
                {
                    名字.删除变量(名字.Get级别());
                    变量列表.Items.Remove(节点);
                    MoyuControl.气泡("删除成功", this);
                    存档();
                }
            });
        }

        private void 列表_KeyDown(object sender, KeyEventArgs e)
        {
            Debug.WriteLine("ctrl+v = " + ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.V));
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.C)
            {
                switch (数据库.选中节点)
                {
                    case string:
                        复制变量_Click(default, default);
                        break;
                    case _方法:
                        复制方法_Click(default, default);
                        break;
                    case _步骤:
                        复制步骤_Click(default, default);
                        break;
                    case _方案:
                        复制方案_Click(default, default);
                        break;
                }
                return;
            }
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.X)
            {
                switch (数据库.选中节点)
                {
                    case string:
                        剪切变量_Click(default, default);
                        break;
                    case _方法:
                        剪切方法_Click(default, default);
                        break;
                    case _步骤:
                        剪切步骤_Click(default, default);
                        break;
                    case _方案:
                        剪切方案_Click(default, default);
                        break;
                }
                return;
            }
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.V)
            {
                switch (前一个复制值)
                {
                    case string:
                        粘贴变量_Click(default, default);
                        break;
                    case _方法:
                        粘贴方法_Click(default, default);
                        break;
                    case _步骤:
                        粘贴步骤_Click(default, default);
                        break;
                    case _方案:
                        粘贴方案_Click(default, default);
                        break;
                }
                return;
            }
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.R)
            {
                switch (前一个复制值)
                {
                    case _方法:
                        替换方法_Click(default, default);
                        break;
                    case _步骤:
                        替换步骤_Click(default, default);
                        break;
                    case _方案:
                        替换方案_Click(default, default);
                        break;
                }
                return;
            }
            if ((Keyboard.Modifiers & ModifierKeys.Control) != 0 && e.Key == Key.D)
            {
                switch (前一个复制值)
                {
                    case _方法:
                        插入方法_Click(default, default);
                        break;
                    case _步骤:
                        插入步骤_Click(default, default);
                        break;
                    case _方案:
                        插入方案_Click(default, default);
                        break;
                }
                return;
            }
            if (e.Key == Key.Delete)
            {
                switch (数据库.选中节点)
                {
                    case string:
                        删除变量_Click(default, default);
                        break;
                    case _方法:
                        删除方法_Click(default, default);
                        break;
                    case _步骤:
                        删除步骤_Click(default, default);
                        break;
                    case _方案:
                        删除方案_Click(default, default);
                        break;
                }
                return;
            }
        }

        public class CursorFeatures
        {
            [DllImport("user32.dll")]
            public static extern bool GetCursorInfo(out CURSORINFO pci);
            [StructLayout(LayoutKind.Sequential)]
            public struct CURSORINFO
            {
                public int cbSize;
                public int flags;
                public IntPtr hCursor;
                public System.Drawing.Point ptScreenPos;
            }
            public static bool Get(out long 特征码)
            {
                特征码 = 0;
                CURSORINFO cursorInfo;
                cursorInfo.cbSize = Marshal.SizeOf(typeof(CURSORINFO));
                if (GetCursorInfo(out cursorInfo))
                {
                    IntPtr hCursor = cursorInfo.hCursor;
                    if (hCursor != IntPtr.Zero)
                    {
                        System.Windows.Forms.Cursor cursor = new System.Windows.Forms.Cursor(hCursor);
                        Bitmap bitmap = new(cursor.Size.Width, cursor.Size.Height);
                        Graphics g = Graphics.FromImage(bitmap);
                        cursor.Draw(g, new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), cursor.Size));
                        using (MemoryStream memoryStream = new MemoryStream())
                        {
                            bitmap.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Png);
                            特征码 = memoryStream.Length;
                            bitmap = null;
                            g.Dispose();
                            return true;
                        }
                    }
                }
                return false;
            }
        }

        private void 下载_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.SaveFileDialog saveFileDialog = new();
            saveFileDialog.Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*";
            saveFileDialog.InitialDirectory = "C:\\Users\\Desktop"; //设置初始目录
            if (!(bool)saveFileDialog.ShowDialog())
                return;
            string name = saveFileDialog.FileName; //获取选择的文件，或者自定义的文件名的全路径.

            string 方案数据 = 数据库.当前方案.CloneStr();

            List<string> 变量s = [.. 数据库.当前方案.子变量];
            Dictionary<string, _变量> 变量m = new();

            foreach (var 步骤 in 数据库.当前方案.步骤)
            {
                foreach (var 步骤变量 in 步骤.子变量)
                    变量s.Add(步骤变量);
            }
            递归(数据库.当前方案.子);
            void 递归(List<_方案> 方案s)
            {
                foreach (var 方案 in 方案s)
                {
                    foreach (var 方案变量 in 方案.子变量)
                        变量s.Add(方案变量);
                    foreach (var 步骤 in 方案.步骤)
                    {
                        foreach (var 步骤变量 in 步骤.子变量)
                            变量s.Add(步骤变量);
                    }
                    递归(方案.子);
                }
            }

            foreach (var item in 变量s)
                变量m.TryAdd(item, 数据库.变量[item]);

            string 变量数据 = 变量m.CloneStr();
            string 总数据 = 方案数据 + "moyufengexian" + 变量数据;

            System.IO.File.WriteAllText(name, 总数据);
            MoyuControl.气泡("保存成功", MainWindow.This);
        }
        private void 上传_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog openFileDialog = new();
            openFileDialog.Filter = "文本文件(*.txt)|*.txt|所有文件(*.*)|*.*";
            openFileDialog.InitialDirectory = "C:\\Users\\Desktop"; //设置初始目录
            if (!(bool)openFileDialog.ShowDialog())
                return;
            string name = openFileDialog.FileName; //获取选择的文件，或者自定义的文件名的全路径.


            string base64 = System.IO.File.ReadAllText(name);
            string[] 数据组 = base64.Split("moyufengexian");

            _方案 新方案 = null;
            byte[] 方案数据 = Convert.FromBase64String(数据组[0]);
            Newtonsoft.Json.JsonSerializer jsonSer = new()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore //避免无限循环
            };
            using (MemoryStream ms = new MemoryStream(方案数据))
            {
                using (BsonReader reader = new BsonReader(ms))
                    新方案 = jsonSer.Deserialize<_方案>(reader);
            }
            if (新方案 == null)
                return;

            Dictionary<string, _变量> 新变量 = new();
            byte[] 变量数据 = Convert.FromBase64String(数据组[1]);
            using (MemoryStream ms = new MemoryStream(变量数据))
            {
                using (BsonReader reader = new BsonReader(ms))
                    新变量 = jsonSer.Deserialize<Dictionary<string, _变量>>(reader);
            }
            foreach (var item in 新变量)
                数据库.变量.TryAdd(item.Key, item.Value);

            方案列表数据.Add(数据库.当前方案, 新方案);
            新方案 = null;
            MoyuControl.气泡("上传成功", MainWindow.This);
            方案列表数据[数据库.当前方案]?.展开();
        }

        private string _主题颜色;
        /// <summary>
        /// 半成品, 无法修改静态资源模板触发器值
        /// </summary>
        public string 主题颜色
        {
            get => _主题颜色;
            set
            {
                var brush = ColorStringToBrushConverter(value);
                this.GS1.Background = brush;
                this.GS2.Background = brush;
                this.GS3.Background = brush;
                this.GS4.Background = brush;
                this.GS5.Background = brush;
                this.GS6.Background = brush;
                this.GS7.Background = brush;
                this.Border1.Background = brush;

                Trigger 选中触发器 = new Trigger
                {
                    Property = TreeViewItem.IsSelectedProperty,
                    Value = true
                };
                Trigger 移过触发器 = new Trigger
                {
                    Property = MyTreeViewHelper.IsMouseDirectlyOverItemProperty,
                    Value = true
                };
                //修改图片
                System.Drawing.Color newColor = ColorTranslator.FromHtml(value);
                Bitmap bitmap = new Bitmap(".\\图标\\节点背景.png");
                for (int y = 0; y < bitmap.Height; y++)
                {
                    for (int x = 0; x < bitmap.Width; x++)
                    {
                        System.Drawing.Color pixelColor = bitmap.GetPixel(x, y);
                        if (pixelColor.A != 0)
                            bitmap.SetPixel(x, y, newColor);
                    }
                }
                var wpfBitmap = bitmap.ToBitmapSource();
                ImageBrush selectedBrush = new ImageBrush { ImageSource = wpfBitmap };
                移过触发器.Setters.Add(new Setter(TreeViewItem.BackgroundProperty, selectedBrush));
                选中触发器.Setters.Add(new Setter(TreeViewItem.BackgroundProperty, selectedBrush));

                // 将触发器添加到样式中
                Style treeViewItemStyle = (Style)MainWindow.This.FindResource(typeof(TreeViewItem));
                treeViewItemStyle.Triggers.Clear();
                treeViewItemStyle.Triggers.Add(选中触发器);
                treeViewItemStyle.Triggers.Add(移过触发器);
            }
        }
        private Brush ColorStringToBrushConverter(string colorString)
        {
            var resul = ColorConverter.ConvertFromString(colorString);
            if (resul == null)
                resul = ColorConverter.ConvertFromString("#FF1BE0D2");
            return new SolidColorBrush((Color)resul);
        }

        private void LayoutChange(object sender, DragCompletedEventArgs e)
        {
            var rowLayout = MainWindow.This.winLayout.RowDefinitions;
            for (int i = 0; i < rowLayout.Count; i++)
                数据库.winRow[i] = rowLayout[i].ActualHeight;
            var columnLayout = MainWindow.This.winLayout.ColumnDefinitions;
            for (int i = 0; i < columnLayout.Count; i++)
                数据库.winColumn[i] = columnLayout[i].ActualWidth;
            存档();
        }














    }






    public class WindowResizeAdorner : Adorner
    {
        //4条边
        Thumb _leftThumb, _topThumb, _rightThumb, _bottomThumb;
        //4个角
        Thumb _lefTopThumb, _rightTopThumb, _rightBottomThumb, _leftbottomThumb;
        //布局容器，如果不使用布局容器，则需要给上述8个控件布局，实现和Grid布局定位是一样的，会比较繁琐且意义不大。
        Grid _grid;
        UIElement _adornedElement;
        System.Windows.Window _window;
        public WindowResizeAdorner(UIElement adornedElement) : base(adornedElement)
        {
            _adornedElement = adornedElement;
            _window = System.Windows.Window.GetWindow(_adornedElement);
            //初始化thumb
            _leftThumb = new Thumb();
            _leftThumb.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            _leftThumb.VerticalAlignment = VerticalAlignment.Stretch;
            _leftThumb.Cursor = System.Windows.Input.Cursors.SizeWE;
            _topThumb = new Thumb();
            _topThumb.HorizontalAlignment = HorizontalAlignment.Stretch;
            _topThumb.VerticalAlignment = VerticalAlignment.Top;
            _topThumb.Cursor = System.Windows.Input.Cursors.SizeNS;
            _rightThumb = new Thumb();
            _rightThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightThumb.VerticalAlignment = VerticalAlignment.Stretch;
            _rightThumb.Cursor = System.Windows.Input.Cursors.SizeWE;
            _bottomThumb = new Thumb();
            _bottomThumb.HorizontalAlignment = HorizontalAlignment.Stretch;
            _bottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _bottomThumb.Cursor = System.Windows.Input.Cursors.SizeNS;
            _lefTopThumb = new Thumb();
            _lefTopThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _lefTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _lefTopThumb.Cursor = System.Windows.Input.Cursors.SizeNWSE;
            _rightTopThumb = new Thumb();
            _rightTopThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightTopThumb.VerticalAlignment = VerticalAlignment.Top;
            _rightTopThumb.Cursor = System.Windows.Input.Cursors.SizeNESW;
            _rightBottomThumb = new Thumb();
            _rightBottomThumb.HorizontalAlignment = HorizontalAlignment.Right;
            _rightBottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _rightBottomThumb.Cursor = System.Windows.Input.Cursors.SizeNWSE;
            _leftbottomThumb = new Thumb();
            _leftbottomThumb.HorizontalAlignment = HorizontalAlignment.Left;
            _leftbottomThumb.VerticalAlignment = VerticalAlignment.Bottom;
            _leftbottomThumb.Cursor = System.Windows.Input.Cursors.SizeNESW;
            _grid = new Grid();
            _grid.Children.Add(_leftThumb);
            _grid.Children.Add(_topThumb);
            _grid.Children.Add(_rightThumb);
            _grid.Children.Add(_bottomThumb);
            _grid.Children.Add(_lefTopThumb);
            _grid.Children.Add(_rightTopThumb);
            _grid.Children.Add(_rightBottomThumb);
            _grid.Children.Add(_leftbottomThumb);
            AddVisualChild(_grid);
            foreach (Thumb thumb in _grid.Children)
            {
                int thumnSize = 10;
                if (thumb.HorizontalAlignment == HorizontalAlignment.Stretch)
                {
                    thumb.Width = double.NaN;
                    thumb.Margin = new Thickness(thumnSize, 0, thumnSize, 0);
                }
                else
                {
                    thumb.Width = thumnSize;
                }
                if (thumb.VerticalAlignment == VerticalAlignment.Stretch)
                {
                    thumb.Height = double.NaN;
                    thumb.Margin = new Thickness(0, thumnSize, 0, thumnSize);
                }
                else
                {
                    thumb.Height = thumnSize;
                }
                thumb.Background = System.Windows.Media.Brushes.Green;
                thumb.Template = new ControlTemplate(typeof(Thumb))
                {
                    VisualTree = GetFactory(new SolidColorBrush(Colors.Transparent))
                };
                thumb.DragDelta += Thumb_DragDelta;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return _grid;
        }
        protected override int VisualChildrenCount
        {
            get => 1;
        }
        protected override System.Windows.Size ArrangeOverride(System.Windows.Size finalSize)
        {
            //直接给grid布局，grid内部的thumb会自动布局。
            _grid.Arrange(new Rect(new System.Windows.Point(-(_window.RenderSize.Width - finalSize.Width) / 2, -(_window.RenderSize.Height - finalSize.Height) / 2), _window.RenderSize));
            return finalSize;
        }
        //拖动逻辑
        private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
        {
            var c = _window;
            var thumb = sender as FrameworkElement;
            double left, top, width, height;
            if (thumb.HorizontalAlignment == HorizontalAlignment.Left)
            {
                left = c.Left + e.HorizontalChange;
                width = c.Width - e.HorizontalChange;
            }
            else
            {
                left = c.Left;
                width = c.Width + e.HorizontalChange;
            }
            if (thumb.HorizontalAlignment != HorizontalAlignment.Stretch)
                if (width > 63)
                {
                    c.Left = left;
                    c.Width = width;
                }

            if (thumb.VerticalAlignment == VerticalAlignment.Top)
            {
                top = c.Top + e.VerticalChange;
                height = c.Height - e.VerticalChange;
            }
            else
            {
                top = c.Top;
                height = c.Height + e.VerticalChange;
            }

            if (thumb.VerticalAlignment != VerticalAlignment.Stretch)
                if (height > 63)
                {
                    c.Top = top;
                    c.Height = height;
                }

            数据库.winW = this.ActualWidth;
            数据库.winH = this.ActualHeight;
            存档();

        }
        //thumb的样式
        FrameworkElementFactory GetFactory(System.Windows.Media.Brush back)
        {
            var fef = new FrameworkElementFactory(typeof(System.Windows.Shapes.Rectangle));
            fef.SetValue(System.Windows.Shapes.Rectangle.FillProperty, back);
            return fef;
        }
    }


    public static class MyTreeViewHelper
    {
        //
        // 鼠标当前直接位于 TreeViewItem 上（或 null）。
        //
        private static TreeViewItem _currentItem = null;

        //
        // IsMouseDirectlyOverItem:  A DependencyProperty that will be true only on the 
        // TreeViewItem that the mouse is directly over.  I.e., this won't be set on that 
        // parent item.
        //
        // This is the only public member, and is read-only.
        //

        // The property key (since this is a read-only DP)
        private static readonly DependencyPropertyKey IsMouseDirectlyOverItemKey =
            DependencyProperty.RegisterAttachedReadOnly("IsMouseDirectlyOverItem",
                                                typeof(bool),
                                                typeof(MyTreeViewHelper),
                                                new FrameworkPropertyMetadata(null, new CoerceValueCallback(CalculateIsMouseDirectlyOverItem)));

        // The DP itself
        public static readonly DependencyProperty IsMouseDirectlyOverItemProperty =
            IsMouseDirectlyOverItemKey.DependencyProperty;

        // A strongly-typed getter for the property.
        public static bool GetIsMouseDirectlyOverItem(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsMouseDirectlyOverItemProperty);
        }

        // A coercion method for the property
        private static object CalculateIsMouseDirectlyOverItem(DependencyObject item, object value)
        {
            // This method is called when the IsMouseDirectlyOver property is being calculated
            // for a TreeViewItem.  

            if (item == _currentItem)
                return true;
            else
                return false;
        }

        //
        // UpdateOverItem:  A private RoutedEvent used to find the nearest encapsulating
        // TreeViewItem to the mouse's current position.
        //

        private static readonly RoutedEvent UpdateOverItemEvent = EventManager.RegisterRoutedEvent(
            "UpdateOverItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyTreeViewHelper));

        //
        // Class constructor
        //

        static MyTreeViewHelper()
        {
            // Get all Mouse enter/leave events for TreeViewItem.
            EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseEnterEvent, new MouseEventHandler(OnMouseTransition), true);
            EventManager.RegisterClassHandler(typeof(TreeViewItem), TreeViewItem.MouseLeaveEvent, new MouseEventHandler(OnMouseTransition), true);

            // Listen for the UpdateOverItemEvent on all TreeViewItem's.
            EventManager.RegisterClassHandler(typeof(TreeViewItem), UpdateOverItemEvent, new RoutedEventHandler(OnUpdateOverItem));
        }


        //
        //OnUpdateOverItem：此方法是 UpdateOverItemEvent 的侦听器。 收到后，
        //这意味着发送方是最接近鼠标的 TreeViewItem（在树的意义上最接近，
        //不是地理上的）。
        static void OnUpdateOverItem(object sender, RoutedEventArgs args)
        {
            // Mark this object as the tree view item over which the mouse
            // is currently positioned.
            _currentItem = sender as TreeViewItem;

            // Tell that item to re-calculate the IsMouseDirectlyOverItem property
            _currentItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);

            // Prevent this event from notifying other tree view items higher in the tree.
            args.Handled = true;
        }

        //
        // OnMouseTransition:  This method is a listener for both the MouseEnter event and
        // the MouseLeave event on TreeViewItems.  It updates the _currentItem, and updates
        // the IsMouseDirectlyOverItem property on the previous TreeViewItem and the new
        // TreeViewItem.

        static void OnMouseTransition(object sender, MouseEventArgs args)
        {
            lock (IsMouseDirectlyOverItemProperty)
            {
                if (_currentItem != null)
                {
                    // Tell the item that previously had the mouse that it no longer does.
                    DependencyObject oldItem = _currentItem;
                    _currentItem = null;
                    oldItem.InvalidateProperty(IsMouseDirectlyOverItemProperty);
                }

                // Get the element that is currently under the mouse.
                IInputElement currentPosition = Mouse.DirectlyOver;

                // See if the mouse is still over something (any element, not just a tree view item).
                if (currentPosition != null)
                {
                    // Yes, the mouse is over something.
                    // Raise an event from that point.  If a TreeViewItem is anywhere above this point
                    // in the tree, it will receive this event and update _currentItem.

                    RoutedEventArgs newItemArgs = new RoutedEventArgs(UpdateOverItemEvent);
                    currentPosition.RaiseEvent(newItemArgs);
                }
            }
        }
    }
}

